#include "dump.h"
#define  ALIGN_FLAG_START_POS 19
#define  ALIGN_FLAG_END_POS 33
#define  FUNCTION_TYPE 0x20 
#define  NAME_BUFFER_LEN 1024

FILE *fp = NULL;
object_header_t *oh;
object_section_t **sections;
object_symbol_t **s;
object_relocations_t **r;

ui32 characteristics_flags[] = {
	0x00000000, 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
	0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400,
	0x00000800, 0x00001000, 0x00008000, 0x00020000, 0x00020000, 0x00040000,
	0x00080000, 0x00100000, 0x00200000, 0x00300000, 0x00400000, 0x00500000,
	0x00600000, 0x00700000, 0x00800000, 0x00900000, 0x00A00000, 0x00B00000,
	0x00C00000, 0x00D00000, 0x00E00000, 0x01000000, 0x02000000, 0x04000000,
	0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000
}; 
ui8 *characteristics_flags_table[] = 
{
	"", "", "", "", "", "",
	"The section contains executable code", "The section contains initialized data", 
	"The section contains uninitialized data", "", 
	"The section contains comments or other information. The .drectve section has this type", 
	"","", "The section contains COMDAT data", 
	"The section contains data referenced through the global pointer (GP)", 
	"", "", "", "", "1", "2", "4", "8","16", "32", "64", "128", "256", "512", "1024", "2048",
	"4096", "8192", "", "", "", "", "", "Execute", "Read", "Write"
}; 

void dump_cls_constructor( ui8 *fname ){
	if( strlen(fname) != NULL ){
		fp = fopen(fname, "rb+");

		if( fp == NULL ){
			printf("Invalid file path. [%s]", fname);
			exit(!EXIT_SUCCESS); 
		}

		oh = object_header_load(fp);
		s = object_symbol_load(fp, oh);
		sections = object_section_load(fp, oh);
	}
}

void dump_cls_destructor(){
	if( fp != NULL ){
		object_symbol_free(s, oh);
		object_section_free(sections, oh);
		object_header_free(oh);

		fflush(fp);
		fclose(fp);
	}
}

void do_option_1(){
	ui32 i, j, c, byte_align, section_id;

	printf( "\n\nFile Type: COFF OBJECT\n\n  Summary\n\n");
	for( i = 0; i < oh->NumberOfSections; i++ ){
		section_id = symbol_get_section_id( oh, sections[i], s );
		printf("\n\nSECTION HEADER #%d\n", section_id);
		printf("   %s name\n", sections[i]->Name ); 
		printf("       0 physical address\n");
		printf("       %d virtual address\n", sections[i]->VirtualAddress ); 
		printf("      %0X size of raw data\n", sections[i]->SizeOfRawData );
		printf("     %0X file pointer to raw data (%0X to %0X)\n", sections[i]->PointerToRawData, sections[i]->PointerToRawData, (sections[i]->PointerToRawData + sections[i]->SizeOfRawData - 1 ));
		printf("       %0X file pointer to relocation table\n", sections[i]->PointerToRelocations );
		printf("       %0X file pointer to line numbers\n", sections[i]->PointerToLinenumbers );
		printf("       %d number of relocations\n", sections[i]->NumberOfRelocations );
		printf("       %d number of line numbers\n", sections[i]->NumberOfLinenumbers );
		printf("%0X flags\n", sections[i]->Characteristics );

		for( c = 0; c < sizeof( characteristics_flags ) / sizeof(int); c++ ){
			if( ( sections[i]->Characteristics & characteristics_flags[c]) == characteristics_flags[c] ){
				if( c >= ALIGN_FLAG_START_POS && c <= ALIGN_FLAG_END_POS ){
					byte_align = atoi(characteristics_flags_table[c], 10);
				}else if( strlen( characteristics_flags_table[c] ) > 0 ){
					printf("         %s\n", characteristics_flags_table[c] );
				}
			}
		}
		printf("         %d byte align\n", byte_align );

		printf("\nSYMBOLS #%d\n\n", section_id);
		for(c = 0; c < oh->NumberOfSymbols; ){
			if( s[c]->SectionNumber == section_id ){
				if( strcmp(s[c]->sname.Name, sections[i]->Name) != 0 ){
					printf(" %s\n", symbol_get_real_name(fp, oh, s[c]) );
				}
			}
			c += s[c]->NumberOfAuxSymbols + 1;
		}

		if( sections[i]->NumberOfRelocations > 0 ){
			printf("\nRELOCATIONS #%d\n", section_id);
			printf("                                                Symbol    Symbol\n");
			printf(" Offset    Type              Applied To         Index     Name\n");
			printf(" --------  ----------------  -----------------  --------  ------\n");
			r = object_relocations_load(fp, sections[i]);
			for( c = 0; c < sections[i]->NumberOfRelocations; c++ ){
				printf(" %08X  %07X                    00000000  %08X  %s\n", r[c]->VirtualAddress, r[c]->Type, r[c]->SymbolTableIndex, symbol_get_real_name(fp, oh, s[r[c]->SymbolTableIndex]));
			}
			object_relocations_free( r, sections[i] );
		}
	}


	printf("\n\nREFERENCED SYMBOLS\n\n");
	for(c = 0; c < oh->NumberOfSymbols; ){
		if( s[c]->SectionNumber == 0 ){
			printf(" %s\n", symbol_get_real_name(fp, oh, s[c]) );
		}
		c += s[c]->NumberOfAuxSymbols + 1;
	}

	printf("\n\nString Table Size = 0x%0X bytes\n\n  Summary\n\n", string_table_get_lenght(fp, oh));
	for( i = 0; i < oh->NumberOfSections; i++ ){
		printf("          %08X %s\n", sections[i]->SizeOfRawData, sections[i]->Name ); 
	}
}


void do_option_2(ui8 *fn){
	FILE *fo;
	object_section_t *text_section;
	ui32 text_section_id, j;

	fo = fopen(fn, "w");
	if( fo == NULL ){
		printf("can't create file [%s]", fn);
		dump_cls_destructor();
		exit(!EXIT_SUCCESS); 
	}

	text_section = object_section_get_text_section(sections, oh);
	text_section_id = symbol_get_section_id( oh, text_section, s );

	fprintf(fo,"#include <stdio.h>\n\n\n");
	fprintf(fo,"void main(){\n");

	for(j = 0; j < oh->NumberOfSymbols; j++){
		if( s[j]->SectionNumber == text_section_id && ( s[j]->Type & FUNCTION_TYPE ) == FUNCTION_TYPE ){
			fprintf(fo,"  unit_test_%s();\n", symbol_get_real_name(fp, oh, s[j]));
		}
	}

	fprintf(fo,"}\n");

	fclose(fo);
}

void do_option_3( ui8 *osymbol, ui8 *dsymbol){
	ui32 i;
	ui32 rs = 0; //Flag - Replace Symbol

	if( osymbol == NULL || dsymbol == NULL){
		printf("\nInvalid program parameters. Use /c and /d switch.\n");
		return;
	}

	//Verify osymbol as Symbol Table
	for(i = 0; i < oh->NumberOfSymbols; ){
		if( strcmp(s[i]->sname.Name, osymbol) == 0 ){
			if( strlen( dsymbol ) > sizeof(s[i]->sname.Name) ){
				s[i]->sname.lname.Zeroes = 0;
				s[i]->sname.lname.Offset = string_table_add_string(fp, oh, dsymbol);
			}else{
				strcpy( s[i]->sname.Name, dsymbol);
			}

			symbol_set( fp, oh, s[i], i );
			rs += 1;
		}

		i += s[i]->NumberOfAuxSymbols + 1;
	}

	if( rs == 0 ){
		printf("\nInvalid symbol %s.\n", osymbol);
	}
}

void do_option_4(ui32 argc, ui32 option_index, ui8 **argv){
	//                        Development notes
	//               s prefix define source variables 
	//            && d prefix define dependency variables 
	ui32 i, j, s, d, flag_write_source;
	FILE            *s_file                       , *d_file;                          
	object_header_t *s_header                     , *d_header;
	object_symbol_t **s_symbols                   ,**d_symbols;
	ui8             s_name_buffer[NAME_BUFFER_LEN], d_name_buffer[NAME_BUFFER_LEN];

	printf("\n\n");
	printf("SOURCE OBJECT            SYMBOL                              DEPENDENCY OBJECT\n\n");

	for( i = option_index + 1; i < argc;  i++ ){
		flag_write_source = 0;
		s_file = fopen(argv[i], "rb");
		s_header = object_header_load( s_file );
		s_symbols = object_symbol_load( s_file, s_header );
		for(s = 0; s < s_header->NumberOfSymbols; ){
			if( s_symbols[s]->SectionNumber == 0 ){
				for( j = option_index + 1; j < argc;  j++ ){
					if( i != j ){
						d_file = fopen(argv[j], "rb");
						d_header = object_header_load( d_file );
						d_symbols = object_symbol_load( d_file, d_header );
						for( d = 0; d < d_header->NumberOfSymbols; ){							
							if(      d_symbols[d]->SectionNumber > 0  ){
								symbol_get_real_name_with_buffer(s_file, s_header, s_symbols[s], s_name_buffer);
								symbol_get_real_name_with_buffer(d_file, d_header, d_symbols[d], d_name_buffer);															
								if(strcmp(   s_name_buffer ,d_name_buffer) == 0){
									if( flag_write_source == 0 ){
										printf( "%s\n", argv[i]);
										flag_write_source = 1;
									}									
									printf( "                         %s\n", symbol_get_real_name(s_file, s_header, s_symbols[s]));
									printf( "                                                               %s\n", argv[j]);
									break;
							    }
						   }																																		
							d += d_symbols[d]->NumberOfAuxSymbols + 1;
						}						
						object_symbol_free(d_symbols, d_header);								
						object_header_free(d_header);						
						fclose(d_file);
					}
				}
			}

			s += s_symbols[s]->NumberOfAuxSymbols + 1;
		}
		object_symbol_free(s_symbols, s_header);
		object_header_free(s_header);
		fclose(s_file);
	}
}


void dumpcls_show_header(){
	ui8 *tostring; 
	ui32 i;

	tostring = object_header_to_xml_string(oh);
	printf("<header>%s", tostring, object_header_section_table_position(oh));
	object_header_to_string_free(tostring);		  	  
}

void dumpcls_close_header(){
	printf("</header>");
}

void dumpcls_show_symbol(){
	ui8 *tostring; 
	ui32 i;

	for(i = 0; i < oh->NumberOfSymbols; i++){
		tostring = object_symbol_to_xml_string(s[i]);
		printf("<symbol id=\"%d\">%s</symbol>", i, tostring);
		object_symbol_to_string_free(tostring);
	}
}

void dumpcls_show_section(){
	ui8 *tostring; 
	ui32 i;

	for( i = 0; i < oh->NumberOfSections; i++ ){
		tostring = object_section_to_xml_string(sections[i]);
		printf("<section id=\"%d\">%s", i, tostring);
		object_section_to_string_free(tostring); 

		printf("</section>");
	}
}